/*
 * Copyright (C) 2008 Google Inc.
 * Copyright (C) 2008 Sean C. Sullivan
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package gtranslate;

import gtranslate.internal.http.GzipRequestInterceptor;
import gtranslate.internal.http.GzipResponseInterceptor;

import java.net.URLEncoder;
import java.util.Map;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.params.AllClientPNames;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;

/**
 * Makes the Google Translate API available to Java applications.
 *
 * @author Richard Midwinter
 * @author Emeric Vernat
 * @author Juan B Cabral
 * @author Cedric Beust
 * @author Sean C. Sullivan
 * 
 */
public class Translator {
    
    private static final String CHARSET = "UTF-8";
    private static final String URL_STRING = "http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&langpair=";
    private static final String TEXT_PARAM = "&q=";

    private HttpClient httpClient;
    private boolean compressionEnabled = false;
    
	public Translator()
	{
		this(new DefaultHttpClient());
	}
	
	public Translator(HttpClient hClient)
	{
		this.httpClient = hClient;
	

		//
		//  this user agent string has been crafted this way
		//  so that Google's service will return gzip compressed responses
		//  to our application when we ask for gzip content
		//
		
		setUserAgent("Mozilla/5.0 (Java) Gecko/20081007 gtranslate-java-client");
		
		setConnectionTimeout( 10 * 1000 );
		setSocketTimeout( 25 * 1000 );
		
		
	}
    
    /**
     * Translates text from a given language to another given language using Google Translate
     *
     * @param text The String to translate
     * @param from The language code to translate from
     * @param to The language code to translate to
     * 
     * @return The translated String
     * 
     * @throws RuntimeException
     * 
     */
    public String translate(String text, Language from, Language to)  
    {
            StringBuilder url = new StringBuilder();
            
            url.append(URL_STRING).append(from.getCode()).append("%7C").append(to.getCode());
            url.append(TEXT_PARAM).append(encodeParameter(text));

            String result = sendHttpGet(url, (Map<String, String>) null);
            
            try
            {
	            JSONObject json = new JSONObject(result);
	            return ((JSONObject)json.get("responseData")).getString("translatedText");
            }
            catch (Exception ex)
            {
            	throw new RuntimeException(ex);
            }
    }

    
	protected String sendHttpGet(CharSequence url, Map<String, String> params)
	{
		HttpClient c = getHttpClient();
		
		HttpUriRequest request = null;
		
		String queryString = buildQueryString(params);
		
		url = url + queryString;
		
		System.out.println(url);
		
		request = new HttpGet(url.toString());
	
		HttpResponse response = null;
		HttpEntity entity = null;
		
		try
		{
			response = c.execute(request);

			int statusCode = response.getStatusLine().getStatusCode();
			
			if (statusCode != HttpStatus.SC_OK)
			{
				throw new RuntimeException("unexpected HTTP response, status code = " + statusCode);
			}
			
			entity = response.getEntity();
			
			return EntityUtils.toString(entity);
		}
		catch (Exception ex)
		{
			throw new RuntimeException(ex);
		}
		finally
		{
			// todo : code here ?
		}
		
	}

	private String buildQueryString(Map<String, String> params)
	{
		if (params == null)
		{
			return "";
		}
		
		StringBuffer query = new StringBuffer();
		
		if (params.size() > 0)
		{
			query.append("?");
			
			for (String key : params.keySet())
			{
				query.append(key);
				query.append("=");
				query.append(encodeParameter(params.get(key)));
				query.append("&");
			}
			
			if (query.charAt(query.length() - 1) == '&')
			{
				query.deleteCharAt(query.length() - 1);
			}
		}			
		
		return query.toString();
	}

	protected String encodeParameter(String s)
	{
		try
		{
			return URLEncoder.encode(s, CHARSET);
		}
		catch (Exception ex)
		{
			throw new RuntimeException(ex);
		}
	}

	protected HttpClient getHttpClient()
	{
		
		if (this.httpClient instanceof DefaultHttpClient)
		{
			DefaultHttpClient defaultClient = (DefaultHttpClient) httpClient;
			
			defaultClient.removeRequestInterceptorByClass(GzipRequestInterceptor.class);
			defaultClient.removeResponseInterceptorByClass(GzipResponseInterceptor.class);
			
			if (this.isCompressionEnabled())
			{
				defaultClient.addRequestInterceptor(GzipRequestInterceptor.getInstance());
				defaultClient.addResponseInterceptor(GzipResponseInterceptor.getInstance());
			}
			
		}

		return this.httpClient;
	}

	public boolean isCompressionEnabled()
	{
		return compressionEnabled;
	}

	public void setCompressionEnabled(boolean b)
	{
		this.compressionEnabled = b;
	}

	public void setUserAgent(String ua)
	{
		this.httpClient.getParams().setParameter(AllClientPNames.USER_AGENT, ua);
	}
	
	public void setConnectionTimeout(int milliseconds)
	{
		httpClient.getParams().setIntParameter(AllClientPNames.CONNECTION_TIMEOUT, milliseconds);
	}
	
	public void setSocketTimeout(int milliseconds)
	{
		httpClient.getParams().setIntParameter(AllClientPNames.SO_TIMEOUT, milliseconds);
	}
	
}